package com.sunlands.qdcy.deskmate.config;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.Assert;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

@Configuration
public class RedisConfig {

    /**
     * 注解里的字符串值必须使用字面量或者常量,所以单独定义常量, 同时用在注解和Cache定义中
     */
    public static class CacheKeys {
        private CacheKeys() {
        }

        public static final String ANDROID_TYPE = "tongzhuo:pay-center:android:pay-type";
        public static final String CHECK_ORDER = "tongzhuo:pay-center:check-order";
        public static final String SEND_GOODS = "tongzhuo:pay-center:send-goods";
        public static final String RETURN_GOODS = "tongzhuo:pay-center:return-goods";
        public static final String WAITING_PAY_ORDER_OUT_TRADE_NO = "tongzhuo:order:waiting-pay";


    }

    /**
     * 这里记录cache key和过期时间
     */
    private enum CacheEnum {

        /**
         *
         */
//        APP_VERSION(CacheKeys.APP_VERSION, 5 * 60),
        ;

        public final String cacheName;
        public final int expireInSeconds;

        CacheEnum(String cacheName, int expireInSeconds) {
            this.cacheName = cacheName;
            this.expireInSeconds = expireInSeconds;
        }
    }
    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setUsePrefix(true);
        //缓存默认60秒, 如果特别情况在CacheEnum里设置
        cacheManager.setDefaultExpiration(60);

        Map<String, Long> expires = Arrays.stream(RedisConfig.CacheEnum.values())
                .collect(Collectors.toMap(e -> e.cacheName, e -> Long.valueOf(e.expireInSeconds)));

        cacheManager.setExpires(expires);
        return cacheManager;
    }

    /**
     * 存入对象tostring后的信息
     *
     * @return RedisTemplate
     */
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        ObjectMapper objectMapper = new ObjectMapper()
                .findAndRegisterModules()
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        RedisTemplate<String, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer
                = new GenericJackson2JsonRedisSerializer(objectMapper);

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        return redisTemplate;
    }

    static class StringRedisSerializer implements RedisSerializer<Object> {
        private final Charset charset;

        public StringRedisSerializer() {
            this(Charset.forName("UTF8"));
        }

        public StringRedisSerializer(Charset charset) {
            Assert.notNull(charset, "Charset must not be null!");
            this.charset = charset;
        }
        @Override
        public String deserialize(byte[] bytes) {
            return (bytes == null ? null : new String(bytes, charset));
        }
        @Override
        public byte[] serialize(Object object) {
            return (object == null ? null : object.toString().getBytes(charset));
        }
    }








}
